package com.googlecode.ddlutilstool.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.apache.log4j.Logger;
import org.apache.log4j.Priority;

import com.googlecode.ddlutilstool.common.DriverBean;
import com.googlecode.ddlutilstool.common.GuiNameAccessor;
import com.googlecode.ddlutilstool.common.ProfileBean;
import com.googlecode.ddlutilstool.kernel.ExecuteManager;
import com.googlecode.ddlutilstool.kernel.GuiManager;
import com.googlecode.ddlutilstool.kernel.ProfileManager;

/**
 * <p>Class ProfileDialog</p>
 * 
 * <p>This dialog allows the user to add and update DB profiles.
 * It presents the contents of the selected profile, allowing
 * the user to make their required chanages and save it.</p>
 * 
 * <p>The actual editing of the Profiles is handled by the
 * ProfileManager.</p>
 */
@SuppressWarnings("serial")
public class ProfileDialog extends JDialog implements ActionListener {
	private static final Logger mLog = Logger.getLogger(ProfileDialog.class);
	
	private static int DISPLAY_WIDTH = 400;
	private static int DISPLAY_HEIGHT = 350;
	
	private GuiNameAccessor mGuiAccessor;
	
	private JTextField mNameField;
	private JComboBox mDriverList;
	private JTextField mClassnameField;
	private JTextField mUrlHintField;
	private JTextField mUrlField;
	private JTextField mUserField;
	private JTextField mPasswordField;
	private JTextField mSchemaField;
	private JButton mSaveButton;
	private JButton mCancelButton;
	private JButton mTestButton;
	
	private ProfileBean mProfile=null;
	
	/**
	 * @throws java.awt.HeadlessException
	 */
	public ProfileDialog(Frame pParent) throws HeadlessException {
		super(pParent,true);
		mGuiAccessor = new GuiNameAccessor();
		ProfileManager profiles = ProfileManager.getInstance();
		
		setTitle(mGuiAccessor.getString("profile.dialog.title"));
		getContentPane().setLayout(new BorderLayout());
		
		Set<String> driverNames = profiles.getDriverNames();
		
		//create the title
		JPanel titlePanel = new JPanel();
		titlePanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		titlePanel.add(new JLabel(mGuiAccessor.getString("profile.dialog.title")));
		getContentPane().add(titlePanel,BorderLayout.NORTH);
		

		
		
		//create the form
		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new GridLayout(8,1));

		JPanel panel = new JPanel();
		JLabel label = new JLabel(mGuiAccessor.getString("profile.dialog.name"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mNameField = new JTextField();
		mNameField.setPreferredSize(new Dimension(200,24));
		panel.add(mNameField);
		mainPanel.add(panel);
		
		panel = new JPanel();
		label = new JLabel(mGuiAccessor.getString("profile.dialog.type"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mDriverList = new JComboBox();
		for (String driverName : driverNames) {
			mDriverList.addItem(driverName);
		}
		mDriverList.addActionListener(this);
		mDriverList.setPreferredSize(new Dimension(200,24));
		panel.add(mDriverList);
		mainPanel.add(panel);
		
		panel = new JPanel();
		label = new JLabel(mGuiAccessor.getString("profile.dialog.class"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mClassnameField = new JTextField();
		mClassnameField.setEditable(false);
		mClassnameField.setPreferredSize(new Dimension(200,24));
		panel.add(mClassnameField);
		mainPanel.add(panel);
		
		panel = new JPanel();
		label = new JLabel(mGuiAccessor.getString("profile.dialog.hint"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mUrlHintField = new JTextField();
		mUrlHintField.setEditable(false);
		mUrlHintField.setPreferredSize(new Dimension(200,24));
		panel.add(mUrlHintField);
		mainPanel.add(panel);
		
		panel = new JPanel();
		label = new JLabel(mGuiAccessor.getString("profile.dialog.url"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mUrlField = new JTextField();
		mUrlField.setPreferredSize(new Dimension(200,24));
		panel.add(mUrlField);
		mainPanel.add(panel);
		
		panel = new JPanel();
		label = new JLabel(mGuiAccessor.getString("profile.dialog.user"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mUserField = new JTextField();
		mUserField.setPreferredSize(new Dimension(200,24));
		panel.add(mUserField);
		mainPanel.add(panel);
		
		panel = new JPanel();
		label = new JLabel(mGuiAccessor.getString("profile.dialog.password"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mPasswordField = new JTextField();
		mPasswordField.setPreferredSize(new Dimension(200,24));
		panel.add(mPasswordField);
		mainPanel.add(panel);
		
		panel = new JPanel();
		label = new JLabel(mGuiAccessor.getString("profile.dialog.schema"));
		label.setPreferredSize(new Dimension(100,24));
		panel.add(label);
		mSchemaField = new JTextField();
		mSchemaField.setPreferredSize(new Dimension(200,24));
		panel.add(mSchemaField);
		mainPanel.add(panel);
		
		
		getContentPane().add(mainPanel,BorderLayout.CENTER);

		
		
		
		//create the buttons
		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
		mTestButton = new JButton(mGuiAccessor.getImageIcon("profile.dialog.test.img"));
		mTestButton.setToolTipText(mGuiAccessor.getString("profile.dialog.test"));
		mTestButton.addActionListener(this);
		buttonPanel.add(mTestButton);
		mSaveButton = new JButton(mGuiAccessor.getImageIcon("profile.dialog.save.img"));
		mSaveButton.setToolTipText(mGuiAccessor.getString("profile.dialog.save"));
		mSaveButton.addActionListener(this);
		buttonPanel.add(mSaveButton);
		mCancelButton = new JButton(mGuiAccessor.getImageIcon("profile.dialog.cancel.img"));
		mCancelButton.setToolTipText(mGuiAccessor.getString("profile.dialog.cancel"));
		mCancelButton.addActionListener(this);
		buttonPanel.add(mCancelButton);
		
		getContentPane().add(buttonPanel,BorderLayout.SOUTH);
		
		
		setSize(DISPLAY_WIDTH,DISPLAY_HEIGHT);
		setVisible(false);
	}

	/**
	 * Fills out the fields with the contains of
	 * the pProfile parameter.
	 * 
	 * @param pProfile The ProfileBean containing the fields to fill into the editor
	 */
	protected void setProfile(ProfileBean pProfile) {
		mProfile = pProfile;
		if (mProfile!=null) {
			mNameField.setText(pProfile.getName());
			setDriverByClass(pProfile.getDriver());
			mUrlField.setText(pProfile.getUrl());
			mUserField.setText(pProfile.getUser());
			mPasswordField.setText(pProfile.getPassword());
			mSchemaField.setText(pProfile.getSchema());
		}
		else {
			setDriverByClass(null);
			mUrlField.setText(null);
			mUserField.setText(null);
			mPasswordField.setText(null);
			mSchemaField.setText(null);
		}
	}
	
	/**
	 * Called by the setProfile, it updates the ClassName and UrlHints
	 * fields using the driver classname.  It gets the contents
	 * from the ProfileManager.
	 * 
	 * @param pClassName the jdbc driver class
	 */
	protected void setDriverByClass(String pClassName) {
		if (pClassName!=null) {
			DriverBean driver = ProfileManager.getInstance().getDriverByClass(pClassName);
			if (driver!=null) {
				mDriverList.setSelectedItem(driver.getName());
				mClassnameField.setText(driver.getClassname());
				mUrlHintField.setText(driver.getUrlHint());
			}
			else {
				mClassnameField.setText(null);
				mUrlHintField.setText(null);
			}
		}
		else {
			mClassnameField.setText(null);
			mUrlHintField.setText(null);
		}
	}
	
	/**
	 * Called by the setProfile, it updates the ClassName and UrlHints
	 * fields using the driver classname.  It gets the contents
	 * from the ProfileManager.
	 * 
	 * @param pClassName the driver name from the DriverManager list
	 */
	protected void setDriverByName(String pDriverName) {
		if (pDriverName!=null) {
			DriverBean driver = ProfileManager.getInstance().getDriverByName(pDriverName);
			if (driver!=null) {
				mDriverList.setSelectedItem(pDriverName);
				mClassnameField.setText(driver.getClassname());
				mUrlHintField.setText(driver.getUrlHint());
			}
			else {
				mClassnameField.setText(null);
				mUrlHintField.setText(null);
			}
		}
		else {
			mClassnameField.setText(null);
			mUrlHintField.setText(null);
		}
	}
	
	/**
	 * <p>Called when the user clicks a button, it
	 * handles the actions required by the button.</p>
	 * 
	 * <p>It also handles when the user chooses a
	 * different driver from the driver.  It will update
	 * the class and urlhints fields.</p>
	 * 
	 * <p>When Cancel is selected, it closes the
	 * dialog.</p>
	 * 
	 * <p>When Save is selected, it tries to save
	 * the profile using the ProfileManager, and
	 * then closes the dialog.</p>
	 * 
	 * <p>When Test is selected, it uses the 
	 * ProfileManager to create a connection to
	 * the database, and reports the results.</p>
	 */
	public void actionPerformed(ActionEvent e) {
		Object obj = e.getSource();
		if (obj.equals(mDriverList)) {
			String driverName = (String)mDriverList.getSelectedItem();
			setDriverByName(driverName);
		}
		else if (obj.equals(mCancelButton)) {
			mProfile = null;
			setVisible(false);
		}
		else if (obj.equals(mSaveButton)) {
			mProfile = buildProfile();
			
			try {
				ProfileManager.getInstance().setProfile(mProfile);
			}
			catch (IOException ex) {
				GuiManager.getInstance().error(mGuiAccessor.getString("profile.dialog.profile.save.error",ex.getMessage()));
				return;
			}
			mProfile = ProfileManager.getInstance().getProfile(mProfile.getName());
			setVisible(false);
		}
		else if (obj.equals(mTestButton)) {
			ProfileBean profile = buildProfile();
			
			try {
				ExecuteManager.getInstance().testProfile(profile);
			}
			catch (Throwable ex) {
				if (mLog.isEnabledFor(Priority.ERROR)) mLog.error(ex.toString());
				if (mLog.isDebugEnabled()) mLog.debug(ex);
				GuiManager.getInstance().error(mGuiAccessor.getString("profile.dialog.profile.test.error",ex.getMessage()));
				return;
			}
			GuiManager.getInstance().info(mGuiAccessor.getString("profile.dialog.profile.test.success"));
		}
	}

	/**
	 * Builds the profile from the edit fields.
	 * @return
	 */
	private ProfileBean buildProfile() {
		ProfileBean profile = new ProfileBean();
		profile.setName(mNameField.getText());
		profile.setDriver(mClassnameField.getText());
		profile.setUrl(mUrlField.getText());
		profile.setUser(mUserField.getText());
		profile.setPassword(mPasswordField.getText());
		profile.setSchema(mSchemaField.getText());
		return profile;
	}
	
	/**
	 * Displays the modal dialog without a defined
	 * profile.  This is used to create new Profiles.
	 * @return The created Profile, or null if cancelled.
	 */
	public ProfileBean display() {
		return display(ProfileManager.getInstance().createDefaultProfile());
	}
	
	/**
	 * Displays the modal dialog using the passed in
	 * profile to fill out the fields.  This is used
	 * to edit profiles.
	 * 
	 * @param pProfile the field contents
	 * @return the saved Profile, or null if cancelled.
	 */
	public ProfileBean display(ProfileBean pProfile) {
		setProfile(pProfile);
		setLocationRelativeTo(getParent());
		setVisible(true);
		return mProfile;
	}

}
